home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / TURBOPASCAL WIN / OWLDEMOS.PAK / DDEMLCLI.PAS < prev    next >
Pascal/Delphi Source File  |  1992-06-08  |  13KB  |  451 lines

  1. {***************************************************}
  2. {                                                   }
  3. {   Turbo Pascal for Windows                        }
  4. {   Windows 3.1 DDEML Demonstration Program         }
  5. {                                                   }
  6. {   Copyright (c) 1992 by Borland International     }
  7. {                                                   }
  8. {***************************************************}
  9.  
  10. program DDEMLClient;
  11.  
  12. { This is a sample application demonstrating the use of the DDEML APIs in
  13.   a client application.  It uses the DataEntry server application that
  14.   is part of this demo in order to maintain a display of the entered data
  15.   as a bar graph.
  16.  
  17.   You must run the server application first (in DDEMLSRV.PAS), and then
  18.   run this client.  If the server is not running, this application will
  19.   fail trying to connect.
  20.  
  21.   The interface to the server is defined by the list of names (Service,
  22.   Topic, and Items) in the separate unit called DataEntry (DATAENTR.TPU).
  23.   The server makes the Items available in cf_Text format; they are con-
  24.   verted and stored locally as integers.  
  25. }
  26.  
  27. uses Strings, WinTypes, WinProcs, WObjects, Win31, DDEML, ShellAPI, BWCC,
  28.   DataEntry;
  29.  
  30. {$R DDEMLCLI}
  31.  
  32. const
  33.  
  34. { Resource IDs }
  35.  
  36.   id_Menu  = 100;
  37.   id_About = 100;
  38.   id_Icon  = 100;
  39.  
  40.   id_PokeEdit = 201;    { Edit Control in Poke Data dialog }
  41.  
  42. { Menu command IDs }
  43.  
  44.   cm_Request   = 200;
  45.   cm_Poke      = 201;
  46.   cm_Advise    = 202;
  47.   cm_HelpAbout = 300;
  48.  
  49. type
  50.  
  51. { Application main window }
  52.  
  53.   PDDEClientWindow = ^TDDEClientWindow;
  54.   TDDEClientWindow = object(TWindow)
  55.     Inst: Longint;
  56.     CallBackPtr: ^TCallback;
  57.     ServiceHSz : HSz;
  58.     TopicHSz   : HSz;
  59.     ItemHSz    : array [1..NumValues] of HSz;
  60.     ConvHdl    : HConv;
  61.  
  62.     DataSample : TDataSample;
  63.  
  64.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  65.     destructor  Done; virtual;
  66.  
  67.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  68.     function  GetClassName: PChar; virtual;
  69.     procedure SetupWindow; virtual;
  70.  
  71.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  72.  
  73.     procedure CMRequest(var Msg: TMessage);
  74.       virtual cm_First + cm_Request;
  75.     procedure CMPoke(var Msg: TMessage);
  76.       virtual cm_First + cm_Poke;
  77.     procedure CMAdvise(var Msg: TMessage);
  78.       virtual cm_First + cm_Advise;
  79.     procedure CMHelpAbout(var Msg: TMessage);
  80.       virtual cm_First + cm_HelpAbout;
  81.  
  82.     procedure Request(HConversation: HConv); virtual;
  83.   end;
  84.  
  85. { Application object }
  86.  
  87.   TDDEClientApp = object(TApplication)
  88.     procedure InitMainWindow; virtual;
  89.   end;
  90.  
  91. { Initialized globals }
  92.  
  93. const
  94.   DemoTitle : PChar = 'DDEML Demo, Client Application';
  95.  
  96. { Global variables }
  97.  
  98. var
  99.   App: TDDEClientApp;
  100.  
  101.  
  102. { Local Function: CallBack Procedure for DDEML }
  103.  
  104. function CallbackProc(CallType, Fmt: Word; Conv: HConv; hsz1, hsz2: HSZ;
  105.   Data: HDDEData; Data1, Data2: Longint): HDDEData; export;
  106. var
  107.   ThisWindow: PDDEClientWindow;
  108. begin
  109.   CallbackProc := 0;    { See if proved otherwise }
  110.  
  111.   ThisWindow := PDDEClientWindow(App.MainWindow);
  112.  
  113.   case CallType of
  114.     xtyp_Register:
  115.       begin
  116.         { Nothing ... Just return 0 }
  117.       end;
  118.     xtyp_Unregister:
  119.       begin
  120.         { Nothing ... Just return 0 }
  121.       end;
  122.     xtyp_xAct_Complete:
  123.       begin
  124.         { Nothing ... Just return 0 }
  125.       end;
  126.     xtyp_Request, Xtyp_AdvData:
  127.       begin
  128.         ThisWindow^.Request(Conv);
  129.         CallbackProc := dde_FAck;
  130.       end;
  131.     xtyp_Disconnect:
  132.       begin
  133.     MessageBox(ThisWindow^.HWindow, 'Disconnected!',
  134.       Application^.Name, mb_IconStop);
  135.         PostQuitMessage(0);
  136.       end;
  137.   end;
  138. end;
  139.  
  140.  
  141. { TDDEClientWindow Methods }
  142.  
  143. { Constructs an instance of the DDE Client Window.  Constructs the 
  144.   window using the inherited constructor, then initializes the instance
  145.   data.
  146. }
  147. constructor TDDEClientWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  148. var
  149.   I : Integer;
  150. begin
  151.   TWindow.Init(AParent, ATitle);
  152.  
  153.   Inst       := 0;      { Must be zero for first call to DdeInitialize } 
  154.   CallBackPtr:= nil;    { MakeProcInstance is called in SetupWindow    }
  155.   ConvHdl    := 0;
  156.   ServiceHSz := 0;
  157.   TopicHSz   := 0;
  158.   for I := 1 to NumValues do
  159.   begin
  160.     ItemHSz[I]    := 0;
  161.     DataSample[I] := 0;
  162.   end;
  163. end;
  164.  
  165. { Destroys an instance of the Client window.  Frees the DDE string
  166.   handles, and frees the callback proc instance if they exist.  Also 
  167.   calls DdeUninitialize to terminate the conversation.  Then calls on
  168.   the ancestral destructor to finish the job.
  169. }
  170. destructor TDDEClientWindow.Done;
  171. var
  172.   I : Integer;
  173. begin
  174.   if ServiceHSz <> 0 then
  175.     DdeFreeStringHandle(Inst, ServiceHSz);
  176.   if TopicHSz <> 0 then
  177.     DdeFreeStringHandle(Inst, TopicHSz);
  178.   for I := 1 to NumValues do
  179.     if ItemHSz[I] <> 0 then
  180.       DdeFreeStringHandle(Inst, ItemHSz[I]);
  181.  
  182.   if Inst <> 0 then
  183.     DdeUninitialize(Inst);   { Ignore the return value }
  184.  
  185.   if CallBackPtr <> nil then
  186.     FreeProcInstance(CallBackPtr);
  187.  
  188.   TWindow.Done;
  189. end;
  190.  
  191. { Redefines GetWindowClass to give this application its own Icon, and 
  192.   its own menu.
  193. }
  194. procedure TDDEClientWindow.GetWindowClass(var AWndClass: TWndClass);
  195. begin
  196.   TWindow.GetWindowClass(AWndClass);
  197.   AWndClass.hIcon := LoadIcon(AWndClass.hInstance, PChar(id_Icon));
  198.   AWndClass.lpszMenuName := PChar(id_Menu);
  199. end;
  200.  
  201. { Returns the class name of this window.  This is necessary since we
  202.   redefine the inherited GetWindowClass method, above.
  203. }
  204. function TDDEClientWindow.GetClassName: PChar;
  205. begin
  206.   GetClassName := 'TDDEClientWindow';
  207. end;
  208.  
  209. { Completes the initialization of the DDE Server Window.  Performs those 
  210.   actions which require a valid window.  Initializes the use of the DDEML.
  211. }
  212. procedure TDDEClientWindow.SetupWindow;
  213. var
  214.   I     : Integer;
  215.   InitOK: Boolean;
  216. begin
  217.   CallBackPtr := MakeProcInstance(@CallBackProc, HInstance);
  218.  
  219. { Initialize the DDE and setup the callback function. If server is not
  220.   present, call will fail.
  221. }
  222.   if CallBackPtr <> nil then
  223.   begin
  224.     if DdeInitialize(Inst, TCallback(CallBackPtr), AppCmd_ClientOnly,
  225.       0) = dmlErr_No_Error then
  226.     begin
  227.       ServiceHSz:= DdeCreateStringHandle(Inst, DataEntryName, cp_WinAnsi);
  228.       TopicHSz  := DdeCreateStringHandle(Inst, DataTopicName, cp_WinAnsi);
  229.       InitOK := True;
  230.       for I := 1 to NumValues do
  231.       begin
  232.     ItemHSz[I]:= DdeCreateStringHandle(Inst, DataItemNames[I],
  233.       cp_WinAnsi);
  234.         InitOK := InitOK and (ItemHSz[I] <> 0); 
  235.       end;
  236.  
  237.       if (ServiceHSz <> 0) and (TopicHSz <> 0) and InitOK then
  238.       begin
  239.         ConvHdl := DdeConnect(Inst, ServiceHSz, TopicHSz, nil);
  240.         if ConvHdl = 0 then
  241.         begin
  242.       MessageBox(HWindow, 'Can''t start conversation!',
  243.         Application^.Name, mb_IconStop);
  244.           PostQuitMessage(0);
  245.         end
  246.       end
  247.       else
  248.       begin  
  249.     MessageBox(HWindow, 'Can''t create strings!', Application^.Name,
  250.       mb_IconStop);
  251.         PostQuitMessage(0);
  252.       end
  253.     end
  254.     else
  255.     begin
  256.       MessageBox(HWindow, 'Can''t initialize!', Application^.Name,
  257.         mb_IconStop);
  258.       PostQuitMessage(0);
  259.     end;
  260.   end;
  261. end;
  262.  
  263. { Repaints the window on request.  Plots a graph of the current sales
  264.   volume.
  265. }
  266. procedure TDDEClientWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  267. const
  268.   LMarg = 30;    { Left Margin of graph }
  269. var
  270.   Wd, Mid: Integer;
  271.   Step   : Integer;
  272.   I      : Integer;
  273.   Norm   : Integer;
  274.   CRect  : TRect;
  275.   ARect  : TRect;
  276.   ALabel : array [0..10] of Char;
  277.   TextMet: TTextMetric;
  278. begin
  279. { First, find the maximum value, and compute a normalization
  280.   factor based on it.
  281. }
  282.   Norm := 0;
  283.   for I := 1 to NumValues do
  284.   begin
  285.     if abs(DataSample[I]) > Norm then
  286.       Norm := abs(DataSample[I]);
  287.   end;
  288.   if Norm = 0 then Norm := 1;   { Just in case we have all zeros }
  289.  
  290. { Next, paint and label the axes.
  291. }
  292.   GetTextMetrics(PaintDC, TextMet);
  293.   GetClientRect(HWindow, CRect);
  294.   Mid := CRect.Bottom div 2;
  295.   MoveTo(PaintDC, 0, Mid);
  296.   LineTo(PaintDC, CRect.Right, Mid);
  297.   MoveTo(PaintDC, LMarg,      0);
  298.   LineTo(PaintDC, LMarg, CRect.Bottom);
  299.   Str(Norm, ALabel);
  300.   TextOut(PaintDC, 0,0, ALabel, StrLen(ALabel));
  301.   TextOut(PaintDC, 0, Mid-(TextMet.tmHeight div 2), '0', 1);
  302.   Str(-Norm, ALabel);
  303.   TextOut(PaintDC, 0,CRect.Bottom-TextMet.tmHeight, ALabel, StrLen(ALabel));
  304.  
  305. { Now draw the bars based on that Normalized value.  Compute the width
  306.   of the bars so that all will fit in the window, and compute an inter-
  307.   bar space that is approximately 20% of the width of a bar.
  308. }
  309.   SelectObject(PaintDC, CreateSolidBrush(RGB(255, 0, 0)));
  310.   SetBkMode(PaintDC, Transparent);
  311.  
  312.   Wd  := (CRect.Right - LMarg) div NumValues;
  313.   Step:= Wd div 5;
  314.   Wd  := Wd - Step;
  315.   ARect.Left := LMarg + (Step div 2);
  316.   for I := 1 to NumValues do
  317.   begin
  318.     with ARect do
  319.     begin
  320.       Right := Left + Wd;
  321.       Top   := Mid;
  322.       Bottom:= Top - Round((Top-5) * (DataSample[I] / Norm));
  323.       Rectangle(PaintDC, Left, Top, Right, Bottom);
  324.       Bottom:= Top + 20;
  325.       DrawText(PaintDC, DataItemNames[I], -1, ARect, dt_Center);
  326.       Left := Left + Wd + Step;
  327.     end;
  328.   end;
  329.   DeleteObject(SelectObject(PaintDC, GetStockObject(White_Brush)));
  330. end;
  331.  
  332. { Generate a DDE Request in response to the DDE | Request menu selection.
  333. }
  334. procedure TDDEClientWindow.CMRequest(var Msg: TMessage);
  335. begin
  336.   Request(ConvHdl);
  337. end;
  338.  
  339. { Generates a DDE Poke transaction in response to the DDE | Poke
  340.   menu selection.  Requests a value from the user that will be
  341.   poked into DataItem1 as an illustration of the Poke function.
  342. }
  343. procedure TDDEClientWindow.CMPoke(var Msg: TMessage);
  344. var
  345.   DataStr: TDataString;
  346.   PokeDlg: PDialog;
  347.   Ed     : PEdit;
  348. begin
  349.   PokeDlg := New(PDialog, Init(@Self, 'POKEDATA'));
  350.   New(Ed, InitResource(PokeDlg, id_PokeEdit, SizeOf(DataStr)));
  351.   StrCopy(DataStr, '0');
  352.   PokeDlg^.TransferBuffer := @DataStr;
  353.  
  354.   if Application^.ExecDialog(PokeDlg) = IdOK then
  355.   begin
  356.     DdeClientTransaction(@DataStr, StrLen(DataStr) + 1, ConvHdl,
  357.       ItemHSz[1], cf_Text, xtyp_Poke, 1000, nil);
  358.     Request(ConvHdl);
  359.   end;
  360. end;
  361.  
  362. { Toggles the state of the DDE Advise setting in response to the
  363.   DDE | Advise menu selection.  When this is selected, all three
  364.   Items are set for Advising.
  365. }
  366. procedure TDDEClientWindow.CMAdvise(var Msg: TMessage);
  367. var
  368.   TempMenu  : HMenu;
  369.   TempResult: Longint;
  370.   I         : Integer;
  371.   NewState  : Word;
  372.   TransType : Word;
  373. begin
  374.   TempMenu := GetMenu(HWindow);
  375.   if GetMenuState(TempMenu, Msg.WParam, mf_ByCommand) = mf_Unchecked then
  376.   begin
  377.     NewState := mf_Checked;
  378.     TransType:= (xtyp_AdvStart or xtypf_AckReq);
  379.   end
  380.   else
  381.   begin
  382.     NewState := mf_Unchecked;
  383.     TransType:= xtyp_AdvStop;
  384.   end;
  385.  
  386.   for I := 1 to NumValues do
  387.     if DdeClientTransaction(nil, 0, ConvHdl, ItemHSz[I], cf_Text, TransType,
  388.         1000, @TempResult) = 0 then
  389.       MessageBox(HWindow, 'Cannot perform Advise Transaction',
  390.           Application^.Name, mb_IconStop);
  391.  
  392.   CheckMenuItem(TempMenu, Msg.WParam, (mf_ByCommand or NewState));
  393.   DrawMenuBar(HWindow);
  394.  
  395.   if TransType and xtyp_AdvStart <> 0 then Request(ConvHdl);
  396. end;
  397.  
  398. { Posts the about box dialog for the DDE Client.
  399. }
  400. procedure TDDEClientWindow.CMHelpAbout(var Msg: TMessage);
  401. begin
  402.   Application^.ExecDialog(New(PDialog, Init(@Self, PChar(id_About))));
  403. end;
  404.  
  405. { Posts a DDE request to obtain cf_Text data from the server.  Requests
  406.   the data for all fields of the DataSample, and invalidates the window to
  407.   cause the new data to be displayed.  Obtains the data from the Server
  408.   synchronously, using DdeClientTransaction.
  409. }
  410. procedure TDDEClientWindow.Request(HConversation: HConv);
  411. var
  412.   hDdeTemp : HDDEData;
  413.   DataStr  : TDataString;
  414.   Err, I   : Integer;
  415. begin
  416.   if HConversation <> 0 then
  417.   begin
  418.     for I := 1 to NumValues do
  419.     begin
  420.       hDdeTemp := DdeClientTransaction(nil, 0, HConversation, ItemHSz[I],
  421.         cf_Text, xtyp_Request, 0, nil);
  422.       if hDdeTemp <> 0 then
  423.       begin
  424.         DdeGetData(hDdeTemp, @DataStr, SizeOf(DataStr), 0);
  425.         Val(DataStr, DataSample[I], Err);
  426.       end;
  427.     end;
  428.     InvalidateRect(HWindow, nil, True);
  429.   end;
  430. end;
  431.  
  432.  
  433. { TDDEClientApp Methods }
  434.  
  435. { Constructs an instance of the DDE Client Window and installs it as the
  436.   MainWindow of this application.
  437. }
  438. procedure TDDEClientApp.InitMainWindow;
  439. begin
  440.   MainWindow := New(PDDEClientWindow, Init(nil, Application^.Name));
  441. end;
  442.  
  443.  
  444. { Main program }
  445.  
  446. begin
  447.   App.Init(DemoTitle);
  448.   App.Run;
  449.   App.Done;
  450. end.
  451.